package utils

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"image"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/disintegration/imaging"
)

// Allowed image extensions
var allowedExtensions = map[string]bool{
	".jpg":  true,
	".jpeg": true,
	".png":  true,
}

// Check if a file is a valid image
func IsValidImage(file *multipart.FileHeader) (bool, error) {
	// Check file extension
	ext := strings.ToLower(filepath.Ext(file.Filename))
	if !allowedExtensions[ext] {
		return false, fmt.Errorf("unsupported file type: %s", ext)
	}

	// Open the file
	src, err := file.Open()
	if err != nil {
		return false, err
	}
	defer src.Close()

	// DecodeConfig only reads image metadata (faster than full decoding)
	_, _, err = image.DecodeConfig(src)
	if err != nil {
		return false, fmt.Errorf("invalid image format")
	}

	return true, nil
}

// Generate an irreversible SHA-256 hash-based filename
func hashFilename(input string) string {
	hasher := sha256.New()
	hasher.Write([]byte(input))
	return hex.EncodeToString(hasher.Sum(nil))[:32] // Take first 32 chars for a shorter filename
}

// Get file path using hashed filename with directory sharding
func SubdirFilepath(s string, basepath string, filename string) string {
	currentTime := time.Now()
	yearMonth := fmt.Sprintf("%d/%02d", currentTime.Year(), currentTime.Month())

	uploadPath := filepath.Join(basepath, yearMonth)

	hash := hashFilename(s) // Hash user ID
	subdir := hash[:2]                              // First 2 chars as directory
	uploadPath = filepath.Join(uploadPath, subdir)

	subdir = hash[2:4]                             // First 2 chars as directory
	uploadPath = filepath.Join(uploadPath, subdir) // Append subdir to path

	if _, err := os.Stat(uploadPath); os.IsNotExist(err) {
		os.MkdirAll(uploadPath, os.ModePerm) // Ensure directory exists
	}

	return filepath.Join(uploadPath, fmt.Sprintf("%s%s", hash[4:], filepath.Ext(filename)))
}

// Function to trim the top parent path
func TrimTopParentPath(filePath string) string {
	// Clean and split the path into components
	dir, file := filepath.Split(filePath)

	// Check if the directory is empty or we only have a file without directory
	if dir == "" || file == "" {
		return filePath
	}

	// Split the directory path into components
	parts := strings.Split(strings.TrimRight(dir, "/\\"), string(filepath.Separator))

	// If we have only one part (no parent directory), just return the file path as is
	if len(parts) <= 1 {
		return filePath
	}

	// Rebuild the path without the first directory
	trimmedDir := filepath.Join(parts[1:]...) // Take everything except the first part
	return filepath.Join(trimmedDir, file)
}

// 缩放图片:
// 如果图片的高或宽大于参数值，则将图片的宽高调整为参数值
func ResizeImage(filepath string, width int, height int) error {
	// Open the image file
	src, err := imaging.Open(filepath)
	if err != nil {
		return fmt.Errorf("failed to open image: %v", err)
	}

	resized := src
	if src.Bounds().Dx() > width || src.Bounds().Dy() > height {
		resized = imaging.Resize(src, width, height, imaging.Lanczos)
	}

	err = imaging.Save(resized, filepath)
	if err != nil {
		return fmt.Errorf("failed to save resize image: %v", err)
	}

	return nil
}

func ScaleImage(filepath string, width int, height int) error {
	// Open the image file
	src, err := imaging.Open(filepath)
	if err != nil {
		return fmt.Errorf("failed to open image: %v", err)
	}

	resized := src
	if src.Bounds().Dx() > width {
		r := float32(src.Bounds().Dx()) / float32(src.Bounds().Dy())
		h := int(float32(width) / r)
		resized = imaging.Resize(src, width, h, imaging.Lanczos)
	} else if src.Bounds().Dy() > height {
		r := float32(src.Bounds().Dx()) / float32(src.Bounds().Dy())
		w := int(float32(height) * r) 
		resized = imaging.Resize(src, w, height, imaging.Lanczos)
	}

	err = imaging.Save(resized, filepath)
	if err != nil {
		return fmt.Errorf("failed to save resize image: %v", err)
	}

	return nil
}